package SingleMachineArrangeImpl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//最大延迟问题（有准备时间，不可中断）
public class EDDr extends SingleMachineArrange{

    //判断所有工件是否处于就绪状态
    private boolean[] isReady(int t,int[] ready,int[] process){
        //计算最早的交付时间
        int min_due = Integer.MAX_VALUE;
        boolean[] result = new boolean[ready.length];
        for(int i=0;i<ready.length;i++){
            min_due = Math.min(Math.max(t,ready[i]) + process[i],min_due);
        }
        for(int i=0;i<ready.length;i++){
            //已完成的工件不再进入就绪态，直接跳过后续判断
            if(process[i]<=0) continue;
            if(ready[i] < min_due) result[i] = true;
        }
        return result;
    }

    private boolean isComplete(int[] process){
        for (int p : process) {
            if(p>0) return false;
        }
        return true;
    }

    //从就绪工件中选择时间下界最小的工件加工
    private int chooseArtifact(boolean[] is_ready,int[] process, int[] ready, int[] due){
        int art = -1;
        int lb = Integer.MAX_VALUE;
        for (int i=0;i<is_ready.length;i++) {
            if(!is_ready[i]) continue;
            System.out.println("假定当前已加工工件：" + (i+1));
            // process数组会被修改，因此要传入副本
            int[] p = Arrays.copyOf(process,process.length);
            //假定当前工件已加工，计算剩余工件在允许中断时的最小用时
            p[i] = COMPLETE;
            //注：算法会找出延误最小的方案所用的时间
            int bound = new EDDx().getTime(p, ready, due);
            System.out.println("那么加工剩下的工件用时大概为" + bound);
            if(bound < lb){
                lb = bound;
                art = i;
            }
        }
        //返回最小用时最低的工件
        System.out.println("先加工工件" + (art+1) + "用时可能最小");
        return art;
    }

    @Override
    public void solve() {
        if(process==null||ready==null||due==null){
            process = new int[]{4,2,6,5};
            ready = new int[]{0,1,3,5};
            due = new int[]{8,12,11,10};
        }
        int t = 0;
        List<Integer> seq = new ArrayList<>();
        while(!isComplete(process)){
            boolean[] ready1 = isReady(t, ready, process);
            int art = chooseArtifact(ready1, process, ready, due);
            //当前没有可加工的工件，进入下一时刻
            if(art==-1){ t++;continue;}
            t += process[art];
            process[art] = 0;
            seq.add(art+1);
        }
        System.out.println("加工顺序: " + seq);
        System.out.println("用时：" + t);
    }
}
